﻿using System;
using System.Collections;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Security.Cryptography;

namespace LxCore
{
    public class JsList<T> : JsBase, IList<T>, INotifyCollectionChanged, INotifyPropertyChanged
        where T : JsBase
    {
        public JsList()
        {
            ListData = new List<T>();
        }
        public JsList(int capacity)
        {
            ListData = new List<T>(capacity);
        }
        protected List<T> ListData;
        public event NotifyCollectionChangedEventHandler? CollectionChanged;
        public event PropertyChangedEventHandler? PropertyChanged;
        protected void RaisePropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
        protected void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
        {
            CollectionChanged?.Invoke(this, e);
        }
        public int Count => ListData.Count;
        public bool IsReadOnly => false;
        public T this[int index]
        {
            get => ListData[index];
            set
            {
                ListData[index] = value;
                if (value != null)
                {
                    value.Parent = this;
                }
            }
        }
        public int IndexOf(T item)
        {
            return ListData.IndexOf(item);
        }
        public virtual void Add(T item)
        {
            checkBeforeAdd(item);
            ListData.Add(item);
            setParent(item);
            OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, ListData.Count - 1));
        }
        public virtual void Insert(int index, T item)
        {
            checkBeforeAdd(item);
            ListData.Insert(index, item);
            setParent(item);
            OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, index));
        }
        private void checkBeforeAdd(T item)
        {
            if (item == null) return;
            if (item.Parent != null && ReferenceEquals(item.Parent, this))
            {
                throw new InvalidDataException("该项已在某List中");
            }
        }
        private void setParent(T item)
        {
            if (item == null) return;
            item.Parent = this;
        }
        public virtual void RemoveAt(int index)
        {
            if (index < 0 || index >= ListData.Count) return;
            T old = ListData[index];
            ListData.RemoveAt(index);
            if (old != null)
            {
                old.Parent = null;
            }
            OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, old, index));
        }
        public virtual bool Remove(T item)
        {
            if (ListData.Remove(item))
            {
                if (item != null)
                {
                    item.Parent = null;
                }
                OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item));
                return true;
            }
            else
            {
                return false;
            }
        }
        public virtual void Clear()
        {
            foreach (var item in ListData)
            {
                item.Parent = null;
            }
            ListData.Clear();
            OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
        }
        public bool Contains(T item)
        {
            return ListData.Contains(item);
        }

        public void CopyTo(T[] array, int arrayIndex)
        {
            ListData.CopyTo(array, arrayIndex);
        }
        public IEnumerator<T> GetEnumerator()
        {
            return ListData.GetEnumerator();
        }
        IEnumerator IEnumerable.GetEnumerator()
        {
            return ListData.GetEnumerator();
        }
    }
}